import { GAME_PAD_MATRIX_H, GAME_PAD_MATRIX_W } from '../BaseGame';

enum BlockType {
  I, L, J, Z, S, O, T
};

//方块形状定义
const BLOCK_SHAPES: Map<BlockType, Array<Array<number>>> = new Map(
  [
    [BlockType.I, [
      [1, 1, 1, 1]
    ]],
    [BlockType.L, [
      [0, 0, 1],
      [1, 1, 1],
    ]],
    [BlockType.J, [
      [1, 0, 0],
      [1, 1, 1],
    ]],
    [BlockType.Z, [
      [1, 1, 0],
      [0, 1, 1],
    ]],
    [BlockType.S, [
      [0, 1, 1],
      [1, 1, 0],
    ]],
    [BlockType.O, [
      [1, 1],
      [1, 1]
    ]],
    [BlockType.T, [
      [0, 1, 0],
      [1, 1, 1]
    ]]
  ]);


//方块初始化时的位置
const START_XY: Map<BlockType, Array<number>> = new Map(
  [
    [BlockType.I, [3, 0]],
    [BlockType.L, [4, -1]],
    [BlockType.J, [4, -1]],
    [BlockType.Z, [4, -1]],
    [BlockType.S, [4, -1]],
    [BlockType.O, [4, -1]],
    [BlockType.T, [4, -1]]
  ]);


//方块变换时的中心点
const ORIGIN: Map<BlockType, Array<Array<number>>> = new Map(
  [
    [BlockType.I, [
      [1, -1],
      [-1, 1],
    ]],
    [BlockType.L, [
      [0, 0]
    ]],
    [BlockType.J, [
      [0, 0]
    ]],
    [BlockType.Z, [
      [0, 0]
    ]],
    [BlockType.S, [
      [0, 0]
    ]],
    [BlockType.O, [
      [0, 0]
    ]],
    [BlockType.T, [
      [0, 0],
      [0, 1],
      [1, -1],
      [-1, 0]
    ]
    ]
  ]);

export class Block {
  blockType: BlockType
  xy: Array<number>
  shape: Array<Array<number>>
  rotateIndex: number

  constructor(
    blockType: BlockType,
    xy: Array<number>,
    shape: Array<Array<number>>,
    rotateIndex: number
  ) {
    this.blockType = blockType;
    this.xy = xy;
    this.shape = shape;
    this.rotateIndex = rotateIndex;
  }

  fall(step: number = 1): Block {
    return new Block(this.blockType, [this.xy[0], this.xy[1] + step], this.shape, this.rotateIndex)
  }

  left(): Block {
    return new Block(this.blockType, [this.xy[0]-1, this.xy[1]], this.shape, this.rotateIndex)
  }

  right(): Block {
    return new Block(this.blockType, [this.xy[0]+1, this.xy[1]], this.shape, this.rotateIndex)
  }

  rotate(): Block {
    var nextShape = Array(this.shape[0].length).fill([])
    for (let row = 0; row < this.shape.length; row++) {
      for (let col = 0; col < this.shape[row].length; col++) {
        if (nextShape[col].length == 0) {
          nextShape[col] = Array(this.shape.length).fill(0)
        }
        nextShape[col][row] = this.shape[this.shape.length - 1 - row][col];
      }
    }
    var next_xy = [
      this.xy[0] + ORIGIN.get(this.blockType)[this.rotateIndex][0],
      this.xy[1] + ORIGIN.get(this.blockType)[this.rotateIndex][1],
    ];
    var nextRotateIndex = this.rotateIndex + 1 >= ORIGIN.get(this.blockType).length ? 0 : this.rotateIndex + 1;
    this.shape = nextShape;
    this.xy = next_xy;
    this.rotateIndex = nextRotateIndex;

    return new Block(this.blockType, [this.xy[0], this.xy[1]], this.shape, this.rotateIndex)
  }

  isValidInMatrix(matrix: number[][]): boolean {
    if (this.xy[1] + this.shape.length > GAME_PAD_MATRIX_H || this.xy[0] < 0 || this.xy[0] + this.shape[0].length > GAME_PAD_MATRIX_W) {
      return false;
    }
    for (let i = 0; i < matrix.length; i++) {
      const line = matrix[i];
      for (let j = 0; j < line.length; j++) {
        if (line[j] === 1 && this.get(j, i) === 1) {
          return false;
        }
      }
    }
    return true;
  }

  get(x: number, y: number): number | null {
    x -= this.xy[0];
    y -= this.xy[1];
    if (x < 0 || x >= this.shape[0].length || y < 0 || y >= this.shape.length) {
      return null;
    }
    return this.shape[y][x] === 1 ? 1 : null;
  }
}

export namespace BlockFun {
  function fromType(type: BlockType): Block {
    const shape = BLOCK_SHAPES.get(type);
    return new Block(type, START_XY.get(type), shape !, 0);
  }

  export function getRandom(): Block {
    // 生成一个介于 0 和 BlockType 枚举长度之间的随机整数
    const randomIndex = Math.floor(Math.random() * Object.keys(BlockType).length / 2);
    // 根据随机索引获取相应的 BlockType 枚举值
    // const randomType = BlockType[Object.keys(BlockType)[randomIndex]];
    // 使用 fromType 函数创建相应类型的方块并返回
    return fromType(randomIndex);
  }
}


